#include "myGraph.h"
#include <math.h>
#include <QDebug>
#include <QFile>
#include <QList>

/**
 * @brief 图类的初始化函数，用于初始化图的点、边信息
 */
myGraph::myGraph(package *pkg)
{
    this->pkg = pkg;
    Init();
}

void myGraph::Init()
{
    int i,j;
    QString str;

    for(i = 1; i < MAXPOINTNUM; i++)
    {
        point[i].pointName.clear();

        for(j = 1; j < MAXPOINTNUM; j++)
        {
            arc[i][j].prePoint.clear();
            arc[i][j].distance = infinite;
            arc[i][j].bikePass = false;
            arc[i][j].congest = 1;
            arc[i][j].peakPeriod.clear();
            arc[i][j].peakValue.clear();
        }
    }
    pointNum = 0;
    pointBuildingNum.clear();
    pointBuildingNumXiTuCheng = 0;
    pointNumShaHe = 0;
    arcNum = 0;
    arcNumShaHe = 0;

    QFile pointFile(":/file/File/point.txt");
    if( ! pointFile.open(QIODevice::ReadOnly))
        qDebug() << "打开点文件错误";
    QTextStream pointStream(&pointFile);
    for(i = 1; !pointStream.atEnd(); i++)
    {
        QList<QString> line = pointStream.readLine().split(" ");
        QList<QString> name = line.at(0).split("/");
        for(j = 0; j < name.size(); j++)
        {
            point[i].pointName << name.at(j);
        }
        point[i].pointX = line.at(1).toInt();
        point[i].pointY = line.at(2).toInt();
        if((point[i].pointCampus = line.at(3).toInt()) == 1)
        {
            pointNumShaHe++;
        }
        if((point[i].pointType = line.at(4).toInt()) == 1)
        {
            pointBuildingNum << i;
            if(point[i].pointCampus == 1)
                pointBuildingNumXiTuCheng++;
        }
    }
    pointNum = i - 1;
//    qDebug() << "pointBuildingNum:" << pointBuildingNum.size();
//    qDebug() << "pointBuildingNumXiTuCheng:" << pointBuildingNumXiTuCheng;

    QFile arcFile(":/file/File/arc.txt");
    if( ! arcFile.open(QIODevice::ReadOnly))
        qDebug() << "打开边文件错误";
    QTextStream arcStream(&arcFile);
    int a, b;
    for(i = 1; !arcStream.atEnd(); i++)
    {
        QList<QString> line = arcStream.readLine().split(" ");
        QList<QString> peakP = line.at(4).split("/");
        QList<QString> peakV = line.at(5).split("/");
        a = line.at(0).toInt();
        b = line.at(1).toInt();

        InitArc(a, b, line, peakP, peakV);
        InitArc(b, a, line, peakP, peakV);

        if(point[a].pointCampus == 1)
            arcNumShaHe++;
    }
    arcNum = i - 1;
}

void myGraph::InitArc(int a, int b, QList<QString> line, QList<QString> peakP, QList<QString> peakV)
{
    QList<QString> period;
    arc[a][b].prePoint << b;
    arc[a][b].distance = line.at(2).toDouble();
    arc[a][b].bikePass = line.at(3).toInt();
    for(int i = 0; peakP.at(0) != "" && i < peakP.size(); i++)
    {
        period = peakP.at(i).split("-");
        for(int j = 0; j < 2; j++)
        {
            QList<QString> time = period.at(j).split(":");
            int min = time.at(0).toInt() * 60 + time.at(1).toInt();
            arc[a][b].peakPeriod << min;
        }
        arc[a][b].peakValue << peakV.at(i).toDouble();
    }
}

double myGraph::NormalDistribution(double A, double Mu, double Sigma, int x)
{
    return A / (sqrt(2 * M_PI) * Sigma) * pow(M_E, (-pow((x - Mu), 2) / (2 * pow(Sigma, 2))));
}
#define ND NormalDistribution

double myGraph::CalculateCongestion(QTime myTime, int a, int b)
{
    if(arc[a][b].peakPeriod.size() < 2)
        return 1;
    struct arcMessage *tempArc = &arc[a][b];
    int i, min, start, end;
    double x;
    min = myTime.hour() * 60 + myTime.minute();
    for(i = 0; i < tempArc->peakPeriod.size() && min < tempArc->peakPeriod.at(i); i++);
    if(i >= tempArc->peakPeriod.at(0) && i % 2 != 0)
    {
        start = tempArc->peakPeriod.at(i - 1);
        end = tempArc->peakPeriod.at(i);
        x = (double)(min - start) / (end - start) * 60;
        //1 + 50正态分布(30, 10, x, false) + 10正态分布(15, 3, x, false) + 7正态分布(8, 2, x, false) + 5正态分布(4, 2, x, false) + 正态分布(2, 1, x, false)
        tempArc->congest = (1 + ND(1, 2, 1, x) + ND(5, 4, 2, x) + ND(7, 8, 2, x) + ND(10, 15, 3, x) +
                            ND(50, 30, 10, x) + ND(10, 45, 3, x) + ND(7, 52, 2, x) + ND(5, 56, 2, x) + ND(1, 58, 1, x))
                            * (tempArc->peakValue.at((i - 1) / 2) / 2.);
    }
    return tempArc->congest;
}

/**
 * @brief 返回地点在图中对应的编号，无则返回0
 */
int myGraph::string2Num(QString address)
{
    int i, j, start, max;
    int numOfName = 0;  //匹配得到地点编号
    int returnValue;
    if(pkg->inP.campus)
    {
        start = 0;
        max = pointNumShaHe;
    }
    else
    {
        start = pointNumShaHe + 1;
        max = pointNum;
    }
    for(i = start; i <= max; i++)   //查找地图上的所有点
    {
        numOfName = point[i].pointName.size();
        for(j = 0; j < numOfName; j++)  //与输入点的所有名称进行匹配，如果匹配成功，则返回相应序号
        {
            if(! address.compare(point[i].pointName.at(j),address))
            {
                returnValue = i;
            }
        }
    }
    return returnValue;
}

/**
 * @brief 返回编号对应的地点名称，无则为默认名称'\0'
 */
QString myGraph::num2String(int num)
{
    return point[num].pointName.at(0);
}
